package com.yupi.springbootinit.scoring;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.yupi.springbootinit.manager.AiManager;
import com.yupi.springbootinit.model.dto.question.QuestionAnswerDTO;
import com.yupi.springbootinit.model.dto.question.QuestionContentDTO;
import com.yupi.springbootinit.model.entity.App;
import com.yupi.springbootinit.model.entity.Question;
import com.yupi.springbootinit.model.entity.UserAnswer;
import com.yupi.springbootinit.service.AppService;
import com.yupi.springbootinit.service.QuestionService;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@ScoringStrategyConfig(appType = 1,scoringStrategy = 1)
public class AiTestScoringStrategy implements ScoringStrategy{
    @Resource
    private AppService appService;
    @Resource
    private QuestionService questionService;
    @Resource
    private AiManager aiManager;
    @Resource
    private RedissonClient redissonClient;

    private final Cache<String, String> answerCacheMap =
            Caffeine.newBuilder().initialCapacity(1024)
                    // 缓存5分钟移除
                    .expireAfterAccess(5L, TimeUnit.MINUTES)
                    .build();
    private static final String AI_ANSWER_LOCK = "AI_ANSWER_LOCK";




    private static final String AI_TEST_SCORING_SYSTEM_MESSAGE = "你是一位严谨的判题专家，我会给你如下信息：\n" +
            "```\n" +
            "应用名称，\n" +
            "【【【应用描述】】】，\n" +
            "题目和用户回答的列表：格式为 [{\"title\": \"题目\",\"answer\": \"用户回答\"}]\n" +
            "```\n" +
            "\n" +
            "请你根据上述信息，按照以下步骤来对用户进行评价：\n" +
            "1. 要求：需要给出一个明确的评价结果，包括评价名称（尽量简短）和评价描述（尽量详细，大于 200 字）\n" +
            "2. 严格按照下面的 json 格式输出评价名称和评价描述\n" +
            "```\n" +
            "{\"resultName\": \"评价名称\", \"resultDesc\": \"评价描述\"}\n" +
            "```\n" +
            "3. 返回格式必须为 JSON 对象";

    private String getAiTestScoringUserMessage(App app,List<String> choices, List<QuestionContentDTO> questionContentDTOList){
        StringBuilder userMessage = new StringBuilder();
        userMessage.append(app.getAppName()).append("\n");
        userMessage.append(app.getAppDesc()).append("\n");
        List<QuestionAnswerDTO> questionAnswerDTOList = new ArrayList<>();
        for (int i = 0; i < questionContentDTOList.size(); i++) {
            QuestionAnswerDTO questionAnswerDTO = new QuestionAnswerDTO();
            String title = questionContentDTOList.get(i).getTitle();
            String choice = choices.get(i);
            questionAnswerDTO.setTitle(title);
            questionAnswerDTO.setUserAnswer(choice);
            questionAnswerDTOList.add(questionAnswerDTO);
        }
        userMessage.append(JSONUtil.toJsonStr(questionAnswerDTOList));
        return userMessage.toString();
    }

    @Override
    public UserAnswer doScore(List<String> choices, App app) {
//        1，先查询缓存，如果有直接返回
        String key = buildCacheKey(app.getId(), JSONUtil.toJsonStr(choices));
        RLock lock = redissonClient.getLock(AI_ANSWER_LOCK + key);

        String questionContentCahce = answerCacheMap.getIfPresent(key);
        if(StringUtils.isNotBlank(questionContentCahce)){
            UserAnswer userAnswer = JSONUtil.toBean(questionContentCahce, UserAnswer.class);
            userAnswer.setAppId(app.getId());
            userAnswer.setAppType(app.getAppType());
            userAnswer.setScoringStrategy(app.getScoringStrategy());
            userAnswer.setChoices(JSONUtil.toJsonStr(choices));
            return userAnswer;
        }
//        2,缓存未命中，构造请求，ai作答并返回userAnswer
        try {
            boolean res = lock.tryLock(3, 15, TimeUnit.SECONDS);
            if(!res){
                return null;
            }
            Question question = questionService.getOne
                    (new LambdaQueryWrapper<Question>().eq(Question::getAppId, app.getId()));
            String questionContent = question.getQuestionContent();
            List<QuestionContentDTO> questionContentDTOList = JSONUtil.toList(questionContent, QuestionContentDTO.class);
            String userMessage = getAiTestScoringUserMessage(app, choices, questionContentDTOList);
            String result = aiManager.doSyncStableRequest(AI_TEST_SCORING_SYSTEM_MESSAGE, userMessage);
            int start = result.indexOf("{");
            int end = result.lastIndexOf("}");
            result = result.substring(start, end + 1);
            UserAnswer userAnswer = JSONUtil.toBean(result, UserAnswer.class);
            userAnswer.setAppId(app.getId());
            userAnswer.setAppType(app.getAppType());
            userAnswer.setScoringStrategy(app.getScoringStrategy());
            userAnswer.setChoices(JSONUtil.toJsonStr(choices));
//        存入缓存中
            answerCacheMap.put(key, result);
            return userAnswer;
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if(lock!=null && lock.isLocked()){
                if(lock.isHeldByCurrentThread()){
                    lock.unlock();
                }
            }
        }
    }
    private String buildCacheKey(Long appId, String choices){
      return DigestUtils.md5Hex(appId +":"+ choices);
    }
}
